package edu.gatech.coc.sirana;

import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;

import net.util.Debug;
import net.util.File_Util;
import net.util.Out;
import edu.gatech.coc.sirana.exception.SIRANAException;
import edu.gatech.coc.sirana.graph.CycleDetector;
import edu.gatech.coc.sirana.graph.InteractionCycle;
import edu.gatech.coc.sirana.graph.OnlineGraph;
import edu.gatech.coc.sirana.graph.SRCycles;
import edu.gatech.coc.sirana.parser.ClientLogItem;
import edu.gatech.coc.sirana.parser.ClientLogParser;
import edu.gatech.coc.sirana.util.CONSTANT;

public class FDA {	
	public static void main(String args[]) throws IOException, ParseException{
		FDA fda = new FDA();		
		String[] srcFiles	= new File(CONSTANT.USER_DATA_DIR).list();		
		ArrayList<InteractionCycle> cyclesInAllLogs = fda.findCyclesOnlineFromFileList(srcFiles);
		
		HashMap<String, Integer> allActions = new HashMap<String, Integer>();
		for(InteractionCycle ic: cyclesInAllLogs){
			String action = ic.findHeadTailAction();
			
			if (allActions.containsKey(action)){
				int occAction =	allActions.get(action);
				occAction++;
				allActions.put(action, occAction);
			}else{
				allActions.put(action, 1);
			}
		}
		
		String outputDir = CONSTANT.OUTPUT_COMBINE_DIR;
		double threshold = 0.5;
		//batch work;		
		ArrayList<String> detectionOutput = new ArrayList<String>();
		int numReports = 0;
		
		for (int i=0; i<srcFiles.length; i++){
			String f	= srcFiles[i];
			if (!f.endsWith(".log")) continue;
			int singleReport = 0;
			ArrayList<SRCycles> srCycles = fda.findSRCyclesFromFile(CONSTANT.USER_DATA_DIR+srcFiles[i]);
			Out.println("\n\n===" + f + "===");
			for (SRCycles src: srCycles){
				InteractionCycle ic1 = src.getCycles().get(0);
				String action = ic1.findHeadTailAction();				
				int occ = allActions.get(action);
				
				double occRate = (double)occ/allActions.size();
				
				if (occRate < threshold && src.getCycles().size() > 1 ){
					boolean isAdd = true;
					for (int j=0; j< src.getCycles().size(); j++){
						if (src.getCycles().get(j).getItems().size() > 20) {
							isAdd = false;
							j = src.getCycles().size();
						}
					}
					if (isAdd ){
						String report = "===Occ: " + occ + "; Rate: " + occRate + "\n" + src.toString();
						detectionOutput.add(report);
						Out.println(report);
						singleReport++;
					}
				}
			}	
			Out.println("===" + f + " end " + singleReport + " rs-cycles reported===");
			
			numReports+=singleReport;
		}
				
		
		String repSummary	= "Number of rs-cycles:" + detectionOutput.size();		
		detectionOutput.add(repSummary);
		Out.println(repSummary + " rscycles totally checked, " + numReports + " rscycles reported.");
		
		File_Util.string_collections_to_file(detectionOutput, outputDir+"outputAll.txt");	
		Out.println("DONE.");
	}
		
	public ArrayList<InteractionCycle> findCyclesOnlineFromFileList(String[] files) throws IOException{
		ArrayList<InteractionCycle> circlesInAllLogs = new ArrayList<InteractionCycle>();
		for (int i=0; i<files.length; i++){
			if (!files[i].endsWith(".log")) continue;
			Debug.println("Find all cycles from: " + files[i]);
			ClientLogParser clp	= new ClientLogParser(CONSTANT.USER_DATA_DIR + files[i]);
			ArrayList<ClientLogItem> interactionList	= clp.parseLogItems();	
			
			ArrayList<InteractionCycle> circlesInOneLog = new CycleDetector().findCyclesAndRepeatedSequence(interactionList);
			circlesInAllLogs.addAll(circlesInOneLog);
		}
		
		return circlesInAllLogs;
	}
			
	ArrayList<SRCycles> findSRCyclesFromFile(String file) throws IOException{	
		ClientLogParser clp	= new ClientLogParser(file);			
		ArrayList<ClientLogItem> interactionList = clp.parseLogItems();		
		
		CycleDetector cd = new CycleDetector();
		OnlineGraph og = new OnlineGraph();
		og.detectRecursiveInteractionCircles(interactionList);
		
		ArrayList<InteractionCycle> cycles = cd.findCyclesAndRepeatedSequence(interactionList);
		//////////////////////////////////////////////////////////////////		
		ArrayList<SRCycles> srcs	= cd.findSRCycles(cycles, og);
		ArrayList<String> srcsStr	= new ArrayList<String>();
		for (SRCycles src : srcs){
			if (src.getCycles().size() < 2 ) continue;
			
			srcsStr.add("\n===successive repeated cycles===\n");
			srcsStr.add(src.toString());
			srcsStr.add("\n---successive repeated cycles done---\n");			
		}
		srcsStr.add("\n=====" + srcs.size() + " repeated cycles.\n");
		
		Debug.println(srcsStr);
		
		return srcs;
	}
	
//	public ArrayList<String> detect(String inputFile, 
//									String outputFile, 
//									ArrayList<InteractionCycle> cyclesInAllLogs,
//									double threshold) throws IOException, ParseException
//	{					
//		CycleDetector cd = new CycleDetector();
//		ArrayList<InteractionCycle> circlesInOneLog = new CycleDetector().findCombinedCycles(CONSTANT.USER_DATA_DIR + inputFile);
//		ArrayList<SRCycles> srcs	= cd.findSRCycles(circlesInOneLog);
//		
//		ArrayList<String> srcsStr	= new ArrayList<String>();
//		
//		for (SRCycles src : srcs){
//			InteractionCycle ic = src.findItemsRepeated();
//			double freq	= this.computeFrequence(ic, cyclesInAllLogs);
//			
//			if (freq<threshold) {
//				Out.println("===freq:\tthreshold===");				
//				Out.println(Out.formatDoubleValue(freq) + "\t" + threshold);
//				Out.println(src.toString());				
//				FDA.numReport++;
//			}
//			
//			srcsStr.add("===successive repeated cycles===");
//			srcsStr.add("frequence=" + freq);
//			srcsStr.add(src.toString());
//			srcsStr.add("---successive repeated cycles done---");			
//		}
//		srcsStr.add("=====" + srcs.size() + " repeated cycles.");
//
//		File_Helper.string_collections_to_file(srcsStr, outputFile);	
//		
//		return srcsStr;
//	}
	
	private double computeFrequence(InteractionCycle c, ArrayList<InteractionCycle> allC){
		int occurrence = 0;
		
		for (InteractionCycle ic: allC){
			if (c.hasSameAction(ic)) occurrence++;
		}
		
		return (double)occurrence/allC.size();
	}
	
}
